(function($, undefined) {
	
$.widget("ui.table", $.ui.mouse, {
	
	options: {
		menu: null,
		nameCol: 1,
		isEdit: false,
		isDateEdit: false,
		select: null,
		isNodeClick: false,
		controlMenu: null,
		
		isBlur: true,
		editType: []
	},
	
	drag: {
		row_sort: 1,
		multi_select: 2
	},
	
	_create: function() {
		var $s = this, con = $s.element;
		
		// remove left border in first column
		$s._initFirstTdBorder();
		
		// init edit input
		$s._initEditInput();
		
		// init click tr event and click td event
		$s._initClickEvent();
		
		// init context menu
		$s._initContextMenu();
		
		// init drag dotted select area
		$s.line_area = $("<div style='display: none;position: absolute;border: 1px dotted #999;background: transparent;'></div>");
		con.append($s.line_area);
		
		$(document.body).bind("click", function() { if($s.options.isBlur)  $s._blurInput(true);  $s.options.isBlur = true; });
		
		// init table width
		var $ths = $("tr:eq(0) th", con), w = 0;
		$ths.each(function() { w += $(this).width(); });
		con.width(w);
		
		$s._mouseInit();
	},
	
	getRow: function() {
		return $("tr.tr-selected", this.element);
	},
	
	add: function(isNode) {
		var $s = this, tab = $s.element;
		
		var html = "<tr isEdit='Y'" + (isNode ? " isNode='Y'" : "") + ">";
		html += "<td style='border-left: 0;' class='sn'>" + $("tr", tab).size() + "</td>";
		
		var colSize = $("tr:eq(0)", tab).children().size();
		for(var i = 1; i < colSize; i++) {
			html += "<td><div";
			if(isNode && i == $s.options.nameCol)  html += " style='font-weight: bold;'";
			html += "></div></td>";
		}
		
		html += "</tr>";
		
		var $tr = $(html).bind("click", function(e) {
			$("tr", tab).removeClass("tr-selected");
			$(this).addClass("tr-selected");
			e.stopPropagation();
		});
		
		$("td", $tr).bind("click", function() { $s._initTdClick($(this)); });
		
		// if has a selected row, append new row after it
		var $selTr = $("tr.tr-selected", tab);
		var $prevTr = $selTr.size() > 0 ? $selTr : $("tr:last", tab);
		$selTr.size() > 0 ? $selTr.after($tr) : tab.append($tr);
		
		// focus name column
		$s.options.isBlur = false;
		$s._initTdClick($("td:eq(" + $s.options.nameCol + ")", $tr.click()));
		
		// reset new tr's level and parentId
		$s._resetLevel($tr, $prevTr);
		
		$s.resetSn();  // reset sn column
	},
	
	levelUp: function() {
		var $s = this, tab = $s.element, $trs = $s.getRow();
		if($trs.size() == 0)  return;
		
		var $tr = $trs.eq(0), $pTrs = $tr.prevAll("tr[isNode='Y']"), $pTr;
		
		$pTrs.each(function() {
			if((parseInt($(this).attr("level")) + 1) < parseInt($tr.attr("level"))) { $pTr = $(this);  return false; }
		});
		
		var l = parseInt($tr.attr("level")), pl = (!$pTr || $pTr.size() == 0) ? 0 : parseInt($pTr.attr("level"));
		if(l <= pl)  return;
		
		$trs.each(function() {
			// reset level
			var level = parseInt($(this).attr("level")) - 1;
			$(this).attr("level", level);
			
			// reset padding
			var $d = $("td:eq(" + $s.options.nameCol + ") div", this);
			$d.css("padding-left", (level * 18 + 5) + "px");
			
			// set parent node
			$(this).attr("isEdit", "Y").attr("parentId", level == 0 ? "" : $pTr.attr("id"));
		});
		
		if(!$("#saveBtn").attr("disabled") || $("#saveBtn").attr("disabled") == "disabled")  $("#saveBtn").attr("disabled", false);
	},
	
	levelDown: function() {
		var $s = this, tab = $s.element, $trs = $s.getRow();
		if($trs.size() == 0)  return;
		
		var $tr = $trs.eq(0), $pTr = $tr.prevAll("tr[isNode='Y']").eq(0);
		if($pTr.size() == 0)  return;
		
		var l = parseInt($tr.attr("level")), pl = parseInt($pTr.attr("level"));
		if(l > pl)  return;
		
		$trs.each(function() {
			// reset level
			var level = ($(this).attr("level") ? parseInt($(this).attr("level")) : 0) + 1;
			$(this).attr("level", level);
			
			// reset padding
			var $d = $("td:eq(" + $s.options.nameCol + ") div", this);
			$d.css("padding-left", (level * 18 + 5) + "px");
			
			// set parent node
			$(this).attr("isEdit", "Y").attr("parentId", $pTr.attr("id"));
		});
		
		if(!$("#saveBtn").attr("disabled") || $("#saveBtn").attr("disabled") == "disabled")  $("#saveBtn").attr("disabled", false);
	},
	
	color: function(color) {
		var $s = this, tab = $s.element, $trs = $s.getRow();
		if($trs.size() == 0)  return;
		
		$("tr", tab).removeClass("tr-selected");
		$trs.attr("isEdit", "Y").css("background-color", color).attr("color", color);
		
		if(!$("#saveBtn").attr("disabled") || $("#saveBtn").attr("disabled") == "disabled")  $("#saveBtn").attr("disabled", false);
	},
	
	resetSn: function() {
		var $s = this, tab = $s.element;
		
		$("tr:gt(0):visible", tab).each(function(i) {
			$("td:eq(0)", $(this)).text(parseInt(i) + 1);
		});
	},
	
	_initEditInput: function() {
		var $s = this, tab = $s.element;
		
		// init column edit type
		$("tr:eq(0) th", tab).each(function() {
			$s.options.editType.push($(this).attr("editType"));
		});
		
		// init text input
		$s.text_input = $("<input type='text' class='hide' style='height: 29px;margin-left: -5px;' />");
		tab.append($s.text_input);
		
		$s.text_input.bind("click", function(e) { e.stopPropagation(); });
		
		// init calendar input
		if($s.options.isDateEdit) {
			$s.date_input = $("<input type='text' class='hide' style='height: 29px;margin-left: -5px;' />");
			$s.date_input.omCalendar();
			tab.append($s.date_input);
			
			$s.date_input.bind("click", function(e) { e.stopPropagation(); });
		} else {
			$s.date_input = $();
		}
		
		// init select input
		if($s.options.select) {
			$s.select_input = $("#" + $s.options.select);
			$s.select_input.select({ isEdit: true });
		} else {
			$s.select_input = $();
		}
	},
	
	_initTdClick: function($td) {
		var $s = this, tab = $s.element;
		
		// blur other column edit input first
		$s._blurInput(false);
		
		var $d = $("div", $td).hide(), index = $td[0].cellIndex, $input;
		
		// column none edit
		if($s.options.editType[index] == "none") {
			return;
		}
		// column select edit
		else if($s.options.editType[index] == "select") {
			$input = $s.select_input.selectVal($d.attr("val") ? $d.attr("val") : "");
			$td.append($input.width($td.width() + 2).show());
		}
		// column text or date edit
		else if($s.options.editType[index] == "text" || $s.options.editType[index] == "date") {
			$input = $s.options.editType[index] == "text" ? $s.text_input : $s.date_input;
			
			$td.append($input.width($td.width() + 6).val($d.text()).show());
			$input.click().focus();
		}
	},
	
	_blurInput: function(isBody) {
		var $s = this, tab = $s.element, $input, $d;
		
		if($s.text_input.is(":visible"))  $input = $s.text_input;
		else if($s.date_input.is(":visible"))  $input = $s.date_input;
		else if($s.select_input.is(":visible"))  $input = $s.select_input;
		
		if($input && $input.is(":visible"))  $d = $input.prev();
		if(!$input || $input.size() == 0 || !$d || $d.size() == 0)  return;
		
		// get origin display text and input value
		$input.hide();
		var origin = $d.text();
		var value = $input == $s.select_input ? $input.selectText() : $input.val();
		
		// init edit value to display when input blur
		$d.text(value).show();
		if($input == $s.select_input) { $d.attr("val", $input.selectVal());  $("ul.menu-ul").hide(); }
		
		if(isBody)  tab.append($input);
		
		// enable save button and set edit status to td
		if(!$("#saveBtn").attr("disabled") || $("#saveBtn").attr("disabled") == "disabled")  $("#saveBtn").attr("disabled", false);
		
		if(origin.trim() != value.trim()) {
			$d.parent().attr("isEdit", "Y");
			$d.closest("tr").attr("isEdit", "Y");
		}
	},
	
	_initFirstTdBorder: function() {
		var $s = this, tab = $s.element;
		
		$("tr:eq(0) th:eq(0)", tab).css("border-left", "0");
		
		$("tr:gt(0)", tab).each(function() {
			$("td:eq(0)", $(this)).css("border-left", "0");
		});
	},
	
	_initClickEvent: function() {
		var $s = this, tab = $s.element;
		
		$("tr:gt(0)", tab).click(function(e) {
			$("tr", tab).removeClass("tr-selected");
			$(this).addClass("tr-selected");
			
			e.stopPropagation();
		});
		
		if($s.options.isEdit) {
			$("tr" + ($s.options.isNodeClick ? "[isNode='Y']" : ""), tab).each(function() {
				$("td", $(this)).bind("click", function(e) { $s._initTdClick($(this)); });
			});
		}
	},
	
	_initContextMenu: function() {
		var $s = this, tab = $s.element;
		
		if(!$s.options.menu)  return;
		
		$("tr:gt(0)", tab).bind("contextmenu", function(e) {
			$s._blurInput(true);
			
			// control menu
			if($s.options.controlMenu) {
				$s._trigger("controlMenu", null, $(this));
			}
			
			// show menu
			$("#" + $s.options.menu).omMenu("show", e);
			
			// select row
			$("tr", tab).removeClass("tr-selected");
			$(this).addClass("tr-selected");
		});
	},
	
	_resetLevel: function($trs, $prevTr) {
		var $s = this, tab = $s.element;
		
		// get move trs' level and parent id
		var level = 0, parentId = "";
		
		if($prevTr.attr("level")) {
			level = parseInt($prevTr.attr("level"));
			parentId = $prevTr.attr("parentId") ? $prevTr.attr("parentId") : "";
			
			if($prevTr.attr("isNode") == "Y" && $trs.eq(0).attr("isNode") != "Y") {
				level += 1;
				parentId = $prevTr.attr("id") ? $prevTr.attr("id") : $prevTr[0].rowIndex;
			}
		}
		
		// reset move trs' level padding and parent id
		$trs.each(function() {
			var $d = $("td:eq(" + $s.options.nameCol + ") div", $(this));
			$d.css("padding-left", (level * 18 + 5) + "px");
			
			$(this).attr({"level": level, "parentId": parentId});
		});
	},
	
	_mouseCapture: function(event) {
		
		return true;
	},
	
	_mouseStart: function(event) {
		var $s = this, tab = $s.element;
		
		// init drag type, if is drag row for sort or drag for multi select
		$s.DRAGTYPE = event.target.cellIndex == 0 ? $s.drag.row_sort : $s.drag.multi_select; 
		
		if($s.DRAGTYPE == $s.drag.multi_select) {
			$("tr", tab).removeClass("tr-selected");
			
			$s._blurInput(true);
			$s.startPos = {x: event.clientX, y: event.clientY};
			
			$s.line_area.css({"left": event.clientX + "px", "top": event.clientY + "px"}).show();
		}
		else {
			if($("tr.tr-selected", tab).size() == 0) {
				var $tr = $(event.target).closest("tr");
				if($tr.size() > 0)  $tr.click();
			}
				
			$s.line_area.height(0).css("left", 0).show();
		}
	},
	
	_mouseDrag: function(event) {
		var $s = this, tab = $s.element;
		
		if($s.DRAGTYPE == $s.drag.multi_select) {
			var sp = $s.startPos, ep = {x: event.clientX, y: event.clientY};
			$s.endPos = ep;
			
			var x = sp.x < ep.x ? sp.x : ep.x, y = sp.y < ep.y ? sp.y : ep.y;
			var w = Math.abs(sp.x - ep.x), h = Math.abs(sp.y - ep.y);
			
			$s.line_area.css({"left": x + "px", "top": y + "px"}).width(w).height(h);
		}
		else {
			var w = tab.width(), $tr = $(event.target).closest("tr");
			
			if($tr.size() > 0) {
				var t = $tr.offset().top + 29;
				$s.line_area.width(w - 2).css("top", t);
			}
		}
	},
	
	_mouseStop: function(evnet) {
		var $s = this, tab = $s.element;
		
		if($s.DRAGTYPE == $s.drag.multi_select) {
			$("tr", tab).removeClass("tr-selected");
			var sy = $s.startPos.y < $s.endPos.y ? $s.startPos.y : $s.endPos.y;
			var ey = $s.startPos.y < $s.endPos.y ? $s.endPos.y : $s.startPos.y;
			
			
			$("tr:gt(0)", tab).each(function() {
				var t1 = $(this).offset().top, t2 = t1 + $(this).height();
				
				if((sy < t1 && t1 < ey) || (sy < t2 && t2 < ey) || (sy > t1 && ey < t2)) {
					$(this).addClass("tr-selected");
				}
			});
		}
		else {
			var $tr = $(event.target).closest("tr"), $dragTr = $("tr.tr-selected", tab);
			
			if($tr.size() > 0 && $dragTr.size() > 0 && $tr[0] !== $dragTr[0]) {
				// move drag row
				$tr.after($dragTr);
				
				// reset drag row level and parentId
				$s._resetLevel($dragTr, $tr);
				
				$s.resetSn();  // reset sn column
				
				$dragTr.attr("isEdit", "Y");
				if(!$("#saveBtn").attr("disabled") || $("#saveBtn").attr("disabled") == "disabled")  $("#saveBtn").attr("disabled", false);
			}
		}
		
		$s.line_area.hide();
	}
});	
	
})(jQuery);